package dht.statistics;

import java.util.HashMap;

import dht.data.Access;
import dht.data.AccessType;
import dht.data.Message;

public class AccessStatistics {
	public AccessType accessType;
	public int accessCount;
	public double totalWaitingCost;
	public double totalProcessCost;
	public double totalNetworkCost;
	public double minWaitingCost;
	public double minProcessCost;
	public double minNetworkCost;
	public double maxWaitingCost;
	public double maxProcessCost;
	public double maxNetworkCost;
	public HashMap<Integer, Integer> msgFlowSize2Count;
	public Access maxNetWorkCostAccess;

	public AccessStatistics(AccessType accessType) {
		this.accessType = accessType;
		this.accessCount = 0;
		this.totalWaitingCost = 0.0;
		this.totalProcessCost = 0.0;
		this.totalNetworkCost = 0.0;
		this.minWaitingCost = Double.MAX_VALUE;
		this.minProcessCost = Double.MAX_VALUE;
		this.minNetworkCost = Double.MAX_VALUE;
		this.maxWaitingCost = Double.MIN_VALUE;
		this.maxProcessCost = Double.MIN_VALUE;
		this.maxNetworkCost = Double.MIN_VALUE;
		this.msgFlowSize2Count = new HashMap<Integer, Integer>();
		this.maxNetWorkCostAccess = null;
	}

	public void updateStatistics(Access access) {
		double waitingCost = 0.0;
		double processCost = 0.0;
		double networkCost = 0.0;
		for (Message msg : access.messageFlow) {
			waitingCost += msg.waitingCost;
			processCost += msg.processCost;
			networkCost += msg.networkCost;
		}

		accessCount++;
		totalWaitingCost += waitingCost;
		totalProcessCost += processCost;
		totalNetworkCost += networkCost;
		minWaitingCost = Math.min(minWaitingCost, waitingCost);
		minProcessCost = Math.min(minProcessCost, processCost);
		minNetworkCost = Math.min(minNetworkCost, networkCost);
		maxWaitingCost = Math.max(maxWaitingCost, waitingCost);
		maxProcessCost = Math.max(maxProcessCost, processCost);
		if (maxNetworkCost < networkCost) {
			maxNetWorkCostAccess = access;
		}
		maxNetworkCost = Math.max(maxNetworkCost, networkCost);

		int flowSize = access.messageFlow.size();
		if (msgFlowSize2Count.containsKey(flowSize)) {
			msgFlowSize2Count
					.put(flowSize, msgFlowSize2Count.get(flowSize) + 1);
		} else {
			msgFlowSize2Count.put(flowSize, 1);
		}
	}

	public String toString() {
		double averageWaitingCost = totalWaitingCost / accessCount;
		double averageProcessCost = totalProcessCost / accessCount;
		double averageNetworkCost = totalNetworkCost / accessCount;
		String value = "###AccessStatistics begin###\naccessType: "
				+ accessType + " accessCount: " + accessCount
				+ " averageWaitingCost: " + averageWaitingCost
				+ " averageProcessCost: " + averageProcessCost
				+ " averageNetworkCost: " + averageNetworkCost
				+ " minWaitingCost: " + minWaitingCost + " minProcessCost: "
				+ minProcessCost + " minNetworkCost: " + minNetworkCost
				+ " maxWaitingCost: " + maxWaitingCost + " maxProcessCost: "
				+ maxProcessCost + " maxNetworkCost: " + maxNetworkCost + "\n";
		for (Integer size : msgFlowSize2Count.keySet()) {
			value += "msgFlowSize: " + size + " Count: "
					+ msgFlowSize2Count.get(size) + "\n";
		}
		if (maxNetWorkCostAccess != null) {
			value += maxNetWorkCostAccess.toString();
		}
		value += "###AccessStatistics end###\n";
		return value;
	}

}
